#pragma once

#include <iostream>
#include <vector>
#include <string>
#include <unordered_map>
#include <cassert>

#include "../comm/util.hpp"
#include "../comm/log.hpp"
namespace ns_model
{
    using namespace ns_util;
    using namespace ns_log;

    struct Question
    {
        std::string number;
        std::string title;
        std::string star;
        int cpu_limit;
        int mem_limit;
        std::string desc;
        std::string header;
        std::string tail;
    };

    class model
    {
        std::string _questions_list = "./questions/questions.list";
        std::string _question_number = "./questions/";

    private:
        std::unordered_map<std::string, struct Question> questions;

    public:
        model()
        {
            assert(LoadQuestionList(_questions_list));
        }

        bool LoadQuestionList(const std::string &question_list)
        {
            std::ifstream in(question_list);
            if (!in.is_open())
            {
                LOG(Fatal) << "打开题库失败,请检查题库完整性" << "\n";
                return false;
            }

            std::string line;
            while (std::getline(in, line))
            {
                std::vector<std::string> tokens;
                StringUtil::Splitstr(line, &tokens, " ");

                if (tokens.size() != 5)
                {
                    LOG(Warning) << "部分题目获取失败" << "\n";
                    continue;
                }
                struct Question q;
                q.number = tokens[0];
                q.title = tokens[1];
                q.star = tokens[2];
                q.cpu_limit = atoi(tokens[3].c_str());
                q.mem_limit = atoi(tokens[4].c_str());

                std::string path = _question_number;
                path += q.number;
                path += "/";

                FileUtil::ReadFile(path + "desc.txt", &(q.desc), true);
                FileUtil::ReadFile(path + "header.cc", &(q.header), true);
                FileUtil::ReadFile(path + "tail.cc", &(q.tail), true);

                questions.insert({q.number, q});
            }
            in.close();
            LOG(Info) << "题目获取完成" << "\n";
            return true;
        }

        bool GetAllQuestion(std::vector<struct Question> *out)
        {
            if (questions.size() == 0)
            {
                LOG(Errer) << "用户题库获取失败" << "\n";
                return false;
            }
            for (const auto &q : questions)
            {
                out->push_back(q.second);
            }
            return true;
        }

        bool GetOneQuestion(const std::string &number, struct Question *out)
        {
            const auto &itqs = questions.find(number);
            if (itqs == questions.end())
            {
                LOG(Error) << "用户题目获取失败 编号: " << number << "\n";
                return false;
            }
            *out = itqs->second;
            return true;
        }

        ~model()
        {
        }
    };
}